import multiprocessing
from concurrent.futures import ThreadPoolExecutor
from tkinter.filedialog import askdirectory
from tkinter import scrolledtext
from xml.dom.minidom import parse
import threading
import tkinter as tk
import tkinter.ttk
from queue import Queue
import datetime
import paramiko 
import psycopg2
import pathlib
import zipfile
import math
import copy
import time
import sys
import re
import os

q = Queue(1)
q.put(0,block=True)
mutex = multiprocessing.Lock()

# select sentinel2 l1c zip file path
def select_tile_date_zips(tile, date, maxcloud=100):
	con = psycopg2.connect(
        database="sentinel2",
        user="postgres",
        password="12345",
        host="192.168.2.172",
        port="5432"
	)
	cur = con.cursor()
	sql = f"""
        SELECT path
        FROM l1c_zip_info 
        WHERE shot_date = to_date('{date}','yyyymmdd')
        AND tile = '{tile}'
        AND clouds <= {maxcloud}
	"""
	cur.execute(sql)
	con.commit()
	paths = [record[0] for record in cur.fetchall()]
	cur.close()
	con.close()
	return paths

# 获取1c含云量
def read_cloud(zipFilePath):
	""""""
	xmlFilePathRe = "^S2.*\.SAFE/MTD_MSIL1C\.xml$"
	zipFile = zipfile.ZipFile(zipFilePath, "r")
	zipFileInfos = zipFile.infolist()
	for zipFileInfo in zipFileInfos:
		if re.match(xmlFilePathRe, zipFileInfo.filename):
			xmlFilePath = zipFile.open(zipFileInfo.filename, "r")
			domTree = parse(xmlFilePath)
			collection = domTree.documentElement
			cloudPercentElement = collection.getElementsByTagName("Cloud_Coverage_Assessment")[0]
			cloudPercent = round(float(copy.deepcopy(cloudPercentElement.childNodes[0].data)))
	return cloudPercent

# 主动入库
def zip_import_sql(file_path, linux_path):
    if not os.path.exists(file_path):
        print(file_path, "not")
    size = os.path.getsize(file_path)
    size = round(size/(1024*1024),2)
    name = os.path.basename(file_path)
    infos = os.path.splitext(name)[0].split("_")
    shot = datetime.datetime.strptime(infos[2], "%Y%m%dT%H%M%S")
    load = datetime.datetime.strptime(infos[6], "%Y%m%dT%H%M%S")
    tile = infos[5][1:]
    cloud = read_cloud(file_path)
    sql = f'''
            INSERT INTO l1c_zip_info (name, level, clouds, tile, size, path, shot_date, load_date) 
            VALUES ('{name}', 'L1C', {cloud}, '{tile}', {size}, '{linux_path}', '{shot}', '{load}')
            on conflict (path) do nothing
        '''   # 字段唯一值冲突则不更新

    con = psycopg2.connect(
        database="sentinel2",
        user="postgres",
        password="12345",
        host="192.168.2.172",
        port="5432"
    )
    cur = con.cursor()	
    cur.execute(sql)
    con.commit()
    cur.close()
    con.close()
    return 


# ui
class my_ui:


    width, height = 750, 600
    line_height = 50
    thread_num = 1
    temp_file_name = ""
    start_time = 0
    start_size = 0

    width, height = 850, 600
    thread_num = 10


    def __init__(self):
        self.get_window()
        self.zip_folder = tk.StringVar()

        line_iter = iter(range(50))
        
        self.zip_folder_frame(next(line_iter))
        self.start_frame(next(line_iter))
        self.progressbar_frame(next(line_iter))
        self.print_frame(next(line_iter))

        self.zip_folder_select(0)
        self.update_start_select(1)
        self.progressbar_select(2)
        self.print_reulst_select(3)

        self.window.mainloop()

    def select_path(self):
        _path = askdirectory()
        _path = _path.replace('/','\\')
        self.zip_folder.set(_path)
        return

    def get_window(self):
        self.window = tk.Tk()
        self.window.title('Sentinel-2数据（L1C）上传工具')
        screenwidth = self.window.winfo_screenwidth() # 屏幕宽度
        screenheight = self.window.winfo_screenheight() # 屏幕高度
        x = int((screenwidth - self.width) / 2)
        y = int((screenheight - self.height) / 2)
        locat = f"{self.width}x{self.height}+{x}+{y}"
        self.window.geometry(locat) # 大小以及位置
        self.window.resizable(0,0) 
        return


    def zip_folder_frame(self, row):
        frame=tkinter.ttk.Frame(self.window,width=self.width)
        frame.place(x=0,y=self.line_height*row)
        tk.Label(
            frame,text="ZIP目录",font=('宋体','14','bold'),height=3
        ).grid(column=0,row=0,sticky='we')  #定义一个标签lable
        self.zip_dir_txt=tk.Entry(
            frame,)
        return

    def zip_folder_select(self, row):
        #定义一个标签lable
        self.tilestr_label = tk.Label(
            self.window,
            text="目标路径",
            font = ('Helvetica', '14', 'bold'),
            # background = 'red',
            # width=6,
            height=3,
         )
        self.tilestr_label.grid(
            column=0, 
            row=row, 
            columnspan=2,
            # padx=(10,0),
            # pady=10,
            sticky=tk.W+tk.E
        )
        #定义一个输入框entry
        self.zip_dir_txt=tk.Entry(
            self.window,
            width=50,
            background = 'white',
            borderwidth = 3,
            relief = 'sunken',
            insertwidth = 3,
            font = ('Helvetica', '14', 'bold'),
            textvariable=self.zip_folder,
            selectforeground = 'red',
            selectbackground = 'blue',
            selectborderwidth = 0,
            show=None

        )  
        self.zip_dir_txt.grid(column=1,row=0,sticky='we')
        self.select_dir_button=tk.Button(
            frame,
            text="选择目录",
            font=('','14','bold'), 
            bg="#50b7c1",
            command=self.select_path
        ) 
        self.select_dir_button.grid(column=2,row=0,sticky='we')
        return

    def start_frame(self, row):
        frame=tkinter.ttk.Frame(self.window,width=self.width)
        frame.place(x=0,y=self.line_height*row)
        self.start_button=tk.Button(
            frame,
            text="开始上传",
            font=('','14','bold'),	
            bg="#50b7c1",
            command=lambda: self.thread_it(self.run_main),
        )
        self.start_button.pack(padx=self.width/2-10,pady=20)
        return

    def progressbar_frame(self,row):
        frame=tkinter.ttk.Frame(self.window,width=self.width)
        frame.place(x=0,y=self.line_height*row)
        tk.Label(
            frame,text="运行进度",font=('宋体','14','bold'),height=3,
        ).grid(column=0,row=0,sticky='we')  #定义一个标签lable
        self.progressbar = tkinter.ttk.Progressbar(
            frame,
            length=640,

        )
        self.zip_dir_txt.grid(
            column=2, 
            row=row, 
            columnspan=10,
            sticky=tk.W+tk.E
        )     
        #定义一个按钮Button
        self.bands_button=tk.Button(
            self.window,
            text="选择目录",
            font=('Helvetica','14','bold'), 
            command=self.select_path
        )
        self.bands_button.grid(
            column=12,
            row=row,
            columnspan=2,
            sticky=tk.W+tk.E
        )
        return

    def update_start_select(self, row):
        #定义一个按钮Button
        self.bands_button=tk.Button(
            self.window,
            text="开启上传",
            font=('','14','bold'),
            # height=3, 
            # command=self.run_main,
            command=lambda: self.thread_it(self.run_main),
        )
        self.bands_button.grid(
            column=6,
            row=row,
            columnspan=2,
            sticky=tk.W+tk.E
        )
        return

    def progressbar_select(self,row):
         #定义一个lable
        self.progressbar_label = tk.Label(
            self.window,
            text="运行进度",
            font = ('Helvetica', '14', 'bold'),
            # width=6,
            height=3,
        )
        self.progressbar_label.grid(
            column=0, 
            row=row, 
            columnspan=2,
            sticky=tk.W+tk.E,
        )
        self.progressbar = tkinter.ttk.Progressbar(
            self.window,
            length=50,

            # maximum=100,
            value=0,
            cursor='spider',
            mode="determinate",
            # mode="indeterminate",

            orient=tk.HORIZONTAL,
        )
        self.progressbar.grid(column=1,row=0,sticky='we')
        return

    def print_frame(self, row):
        frame=tkinter.ttk.Frame(self.window,width=self.width)
        frame.place(x=0,y=self.line_height*row)
        tk.Label(
            frame,text="运行信息",font=('宋体','14','bold'),
        ).grid(column=0,row=0,sticky='we') 
        self.scrolled_text = scrolledtext.ScrolledText(
            frame, 
            state='normal',
            wrap = tk.WORD,
            font=('Times New Roman', 12),
            width=90, 
            height=30,
            
        ) 
        # self.scrolled_text.grid(column=1,row=0,rowspan=20,sticky='we')

        #     orient=tk.HORIZONTAL
        # )
        self.progressbar.grid(
            column=2, 
            row=row, 
            sticky=tk.W+tk.E,
            columnspan=10
        )
        return

    def print_reulst_select(self, row):
        #处理结果展示   
        self.scrolled_text = scrolledtext.ScrolledText(
			self.window, 
			state='normal',
            wrap = tk.WORD,
            font=('Times New Roman', 12),
			width=90, 
			height=30,
        ) 

        self.scrolled_text.configure(font='TkFixedFont')
        self.scrolled_text.tag_config('INFO', foreground='black')
        self.scrolled_text.tag_config('DEBUG', foreground='gray')
        self.scrolled_text.tag_config('WARNING', foreground='orange')
        self.scrolled_text.tag_config('ERROR', foreground='red')
        self.scrolled_text.tag_config('CRITICAL', foreground='red', underline=1)

        self.scrolled_text.grid(
            column=2, 
            row=row, 
            rowspan=15, 
            columnspan=10,
            # pady =10 ,
            # padx = 10,
        )

        return
    
    def message_box(self):
        tk.messagebox.showinfo('Message', '上传完成！')

    def thread_it(self,func,*args):

        # 线程

        t = threading.Thread(target=func, args=args)
        # 守护 !!!
        t.setDaemon(True)
        # 启动
        t.start()
        # 阻塞--卡死界面！
        # t.join()
        return

    def run_main(self):
        folder = r"/home/遥感技术部/遥感数据/Sentinel2L1cZip" 

        self.scrolled_text.configure(state ='normal')

   

        zip_dir = self.zip_dir_txt.get()
        if not os.path.exists(zip_dir):
            return
        file_paths = [
            os.path.join(zip_dir,name)
            for name in os.listdir(zip_dir)
            if re.match("^S2[AB]_MSIL1C_.*\.zip$",name)
        ]


        self.scrolled_text.delete(0.0, tkinter.END)
        self.window.update()
        
        string = f"\n{datetime.datetime.now().strftime('%H:%M:%S')}>开始上传！\n"
        self.scrolled_text.insert(tk.END, string)
        self.scrolled_text.see(tk.END)
        self.scrolled_text.focus()
        self.window.update()

        self.client = paramiko.SSHClient()
        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        # self.client.connect(

        self.scrolled_text.configure(state = 'normal' )
        self.scrolled_text.insert(
            tk.END, f"\n{datetime.datetime.now().strftime('%H:%M:%S')}>开始上传！"
        )
        self.window.update()
    
        self.progressbar["maximum"] = len(file_paths) 
        for index in range(0, len(file_paths), self.thread_num):
            args_list = []
            for file_path in file_paths[index:index+self.thread_num]:
                args_list.append([file_path, folder])
            with ThreadPoolExecutor(max_workers=self.thread_num) as executor:
                results = executor.map(up_sentinel_zip,args_list)
            for i,result in enumerate(results):
                self.scrolled_text.insert(tk.END, result)
                self.window.update()
                self.progressbar["value"] = index+i
                self.window.update()

        self.message_box()
        return

# # update data
# def up_sentinel_zip(args):
#     [path, folder] = args
  
#     zip_name = os.path.basename(path)
#     tile = zip_name.split("_")[5][1:]
#     date = zip_name.split("_")[2][:8]

#     zip_paths = select_tile_date_zips(tile, date, maxcloud=100)
#     if zip_name in [os.path.basename(temp) for temp in zip_paths]:
#         return
#     try:
#         client = paramiko.SSHClient()
#         client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#         client.connect(

#             hostname="192.168.2.172",
#             port=22, 
#             username="root", 
#             password="DELL123dell"
#         )

#         self.sftp: paramiko.SFTPClient = self.client.open_sftp()

#         string = f"{datetime.datetime.now().strftime('%H:%M:%S')}>连接：192.168.2.172！\n"
#         self.scrolled_text.insert(tk.END,string)
#         self.scrolled_text.see(tk.END)
#         self.scrolled_text.focus()
#         self.window.update()

#         self.progressbar["maximum"] = len(file_paths) 
#         for index in range(0, len(file_paths), self.thread_num):
#             file_path = file_paths[index]
#             string = self.up_sentinel_zip([file_path, folder])
#             self.scrolled_text.insert(tk.END,string)
#             self.scrolled_text.see(tk.END)
#             self.scrolled_text.focus()
#             self.window.update()
#             self.progressbar["value"] = index+1
#             self.window.update()

#             # args_list = []
#             # for file_path in file_paths[index:index+self.thread_num]:
#                 # args_list.append([file_path, folder])
#             # with ThreadPoolExecutor(max_workers=self.thread_num) as executor:
#             #     results = executor.map(up_sentinel_zip,args_list)
#             # for i,result in enumerate(results):
#             #     self.scrolled_text.insert(tk.END, result)
#             #     self.window.update()
#             #     self.progressbar["value"] = index+i
#             #     self.window.update()

#         self.sftp.close()
#         self.client.close()

#         string = f"\n{datetime.datetime.now().strftime('%H:%M:%S')}>断开：192.168.2.172！\n"
#         self.scrolled_text.insert(tk.END,string)
#         self.scrolled_text.see(tk.END)
#         self.scrolled_text.focus()
#         self.window.update()

#         self.scrolled_text.configure(state = 'disabled' )
#         self.message_box()
#         return

#     # update data
#     def up_sentinel_zip(self,args):
#         [path, folder] = args

#         zip_name = os.path.basename(path)
#         self.temp_file_name = zip_name
#         tile = zip_name.split("_")[5][1:]
#         date = zip_name.split("_")[2][:8]
#         zip_paths = select_tile_date_zips(tile, date, maxcloud=100)

#         if zip_name in [os.path.basename(temp) for temp in zip_paths]:
#             string = f"{datetime.datetime.now().strftime('%H:%M:%S')}>success {zip_name}\n"
#             return string
#         remote_dir = str(pathlib.PurePosixPath(folder, date))
#         remote_path = str(pathlib.PurePosixPath(remote_dir, zip_name))
    
#         try:
#             stat = self.sftp.stat(remote_path)
#             if stat.st_size != os.path.getsize(path):
#                 self.sftp.remove(remote_path)
#                 try:
#                     self.sftp.chdir(remote_dir)
#                 except:
#                     self.sftp.mkdir(remote_dir)
#                     self.sftp.chdir(remote_dir)
#                 self.sftp.put(path, remote_path,callback=self._Callback,confirm=True)
#         except:
#             try:
#                 self.sftp.chdir(remote_dir)
#             except:
#                 self.sftp.mkdir(remote_dir)
#                 self.sftp.chdir(remote_dir)
#             self.sftp.put(path, remote_path,callback=self._Callback,confirm=True)
          
#         zip_import_sql(path,remote_path)
#         string = f"{datetime.datetime.now().strftime('%H:%M:%S')}:success {zip_name}\n"
#         return string
    
#     def _Callback(self,a=10,b=10):
#         percent = round(a*100./int(b),2)
#         if  percent in [i*20.00 for i in range(6)] :
#             if percent == 0:
#                 string = f'\n{self.temp_file_name} {round(a/1024./1024,2)}M {percent}% \n'
#                 self.scrolled_text.insert(tk.END, string)
#                 self.scrolled_text.see(tk.END)
#                 self.window.update()
#                 self.start_time = time.time() 
#             else:
#                 index = float(self.scrolled_text.index(tk.END))
#                 self.scrolled_text.delete(index-2,index)
#                 # speed = round((round(a/1024./1024,2) - self.start_size)/(time.time()-self.start_time))
#                 string = f'\n{self.temp_file_name} {round(a/1024./1024,2)}M {percent}%  \n'
#                 self.scrolled_text.insert(index-1, string)
#                 self.scrolled_text.see(index-1)
#                 self.window.update()
#                 # self.start_time = time.time()
#                 # self.start_size = round(a/1024./1024,2)
#         return


    

#         sftp: paramiko.SFTPClient = client.open_sftp()
#         file_size = math.ceil(os.path.getsize(path)/(1024*1024))
#         remote_path = str(pathlib.PurePosixPath(folder, date, zip_name))
#         _, stdout, _ = client.exec_command(f"du -m {remote_path}")
#         result = stdout.readline().split("\t")[0]
#         remote_dir = str(pathlib.PurePosixPath(folder, date))
#         if result == "":
#             _, stdout, _ = client.exec_command(f"[ -d {remote_dir} ] && echo OK")
#             info = stdout.readline().split("\n")[0]
#             if info != 'OK':
#                 sftp.mkdir(remote_dir)
#             sftp.put(path, remote_path)
#         elif file_size != int(result):
#             _, stdout, _ = client.exec_command(f"rm -f {remote_path}")
#             sftp.put(path, remote_path)
#         client.close()
#         sftp.close()
#         zip_import_sql(path,remote_path)
#         string = f"\n{datetime.datetime.now().strftime('%H:%M:%S')}>success {zip_name}"
#         return string
#     except:
#         string = f"\n{datetime.datetime.now().strftime('%H:%M:%S')}:fail {zip_name}"
#         return string
      



if __name__ == "__main__":
    command=r"net use Z: \\192.168.2.172\root DELL123dell /user:root"
    os.system(command)
    my_ui()